#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/i2c.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/device.h>
#include <linux/time.h>

#include <linux/platform_device.h>
#include "codetab.h"

#define DevName "I2C_device"
#define ClassName "I2C_calss"
#define Send_Commend  0x00
#define Send_Data     0x40

static dev_t devno;
static struct cdev chardev_str; // 字符设备结构体
static struct class* iic_class;
static struct device* iic_dev;
static struct i2c_client* I2C_client = NULL;


static int i2c_write_ssd1306(struct i2c_client *client, u8 address, u8 data)
{
    int error = 0;
	u8 write_data[2];
	struct i2c_msg send_msg; //要发送的数据结构体

    /*设置要发送的数据*/
	write_data[0] = address;
	write_data[1] = data;

	/*发送 iic要写入的地址 reg*/
	send_msg.addr = client->addr;         // iic 总线上的地址
	send_msg.flags = 0;					  //标记为发送数据
	send_msg.buf = write_data;			  //写入的首地址
	send_msg.len = 2;					  //reg长度    

    error = i2c_transfer(client->adapter, &send_msg, 1);
	if (error != 1){
		printk("i2c_transfer error \n");
		return -1;
	}
	return 0;
}

static void i2c_oled_setpots(u8 x, u8 y)
{
    i2c_write_ssd1306(I2C_client, Send_Commend, 0xb0+y);
    i2c_write_ssd1306(I2C_client, Send_Commend, ((x&0xf0)>>4)|0x10);
    i2c_write_ssd1306(I2C_client, Send_Commend, x&0x0f);
}


void OLED_ShowStr(unsigned char x, unsigned char y,char ch[])
{
	int8_t i=0,j=0,c=0;
	while (ch[j] != '\0'){
		c=ch[j]-32;
		if (x > 122){
			x = 0;
			y = y+1;
		}
		i2c_oled_setpots(x,y);
		for (i = 0;i < 6;i++){
            i2c_write_ssd1306(I2C_client, Send_Data, F6x8[c][i]);
			//WriteData(F6x8[c][i]);
        }
            
		x += 6;
		j++;
	}
}





static int ssd1306_init(void)
{
	int error = 0;
    int i = 0, j = 0;
	/*配置oled*/
    msleep(10);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0xAE);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0x20);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0x10);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0xb0);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0xc8);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0x00);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0x10);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0x40);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0x81);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0xff);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0xa1);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0xa6);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0xa8);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0x3F);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0xa4);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0xd3);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0x00);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0xd5);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0xf0);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0xd9);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0x22);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0xda);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0x12);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0xdb);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0x20);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0x8d);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0x14);
    error = i2c_write_ssd1306(I2C_client, Send_Commend, 0xaf);

    for (i=0;i<8;i++){
        error = i2c_write_ssd1306(I2C_client, Send_Commend, 0xb0+i);
        error = i2c_write_ssd1306(I2C_client, Send_Commend, 0x10);
        error = i2c_write_ssd1306(I2C_client, Send_Commend, 0x00);
		for (j=0;j<128;j++){
            error = i2c_write_ssd1306(I2C_client, Send_Data, 0x00);
            msleep(1);
		}
	}
 
	if (error < 0)
	{
		/*初始化错误*/
		printk(KERN_DEBUG "mpu6050_init error \n");
		return -1;
	}
	return 0;
}

static int I2C_open(struct inode *inode, struct file *filp)
{
	printk("ssd1306_init \n");
	ssd1306_init();
	return 0;
}


// static int I2C_write(struct i2c_client *mpu6050_client, u8 address, u8 data)
// {
//    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
//     return 0;
// }



static struct file_operations I2C_fops =
	{
		.owner = THIS_MODULE,
		.open = I2C_open,
		//.write = I2C_write,
};

static int I2C_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret = 0;
    printk(" I2C device probe ... \n");
    ret = alloc_chrdev_region(&devno, 0, 1, DevName);
    if (ret < 0){
        printk(" fail to alloc I2C devno\n");
    }
    cdev_init(&chardev_str, &I2C_fops);
    chardev_str.owner = THIS_MODULE;
    ret = cdev_add(&chardev_str, devno, 1);
    if (ret < 0){
        printk(" fail to add I2C cdev\n");
    }
    iic_class = class_create(THIS_MODULE, ClassName);
    iic_dev = device_create(iic_class, NULL, devno, NULL, DevName);
    I2C_client = client;

	printk("I2C init finished! \n");
    ssd1306_init();
    OLED_ShowStr(2, 2,"abc");
    OLED_ShowStr(5, 5,"eee");
	return 0;
}


static int I2C_remove(struct i2c_client *client)
{
	cdev_del(&chardev_str);				  //清除设备号
	unregister_chrdev_region(devno, 1);  //取消注册字符设备
    device_destroy(iic_class, devno);	  //清除设备
    class_destroy(iic_class);		      //清除类
    printk("I2C exit finished! \n");
	return 0;
}

static const struct i2c_device_id gtp_device_id[] = {
	{"fire,i2c_mpu6050", 0},
	{}};


static const struct of_device_id I2C_of_match_table[] = {
	{.compatible = "yckj,st7789ts"},
	{/* sentinel */}};


struct i2c_driver I2C_driver = {
	.probe = I2C_probe,
	.remove = I2C_remove,
	.id_table = gtp_device_id,
	.driver = {
		.name = "chengreen,I2C",
		.owner = THIS_MODULE,
		.of_match_table = I2C_of_match_table,
	},
};


static int __init I2C_driver_init(void)
{
	int ret;
	pr_info("I2C_driver_init\n");
	ret = i2c_add_driver(&I2C_driver);
	return ret;
}

static void __exit I2C_driver_exit(void)
{
	pr_info("I2C_driver_exit\n");
	i2c_del_driver(&I2C_driver);
}

module_init(I2C_driver_init);
module_exit(I2C_driver_exit);

MODULE_LICENSE("GPL");
